package com.prototype.dao.impl;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;

import com.prototype.dao.BaseDAO;

@Repository(value = "baseDAO")
public abstract class BaseDAOImpl<T extends Serializable> implements BaseDAO<T> {

	@Autowired
	protected HibernateTemplate hibernateTemplate;

	@Autowired
	private SessionFactory sessionFactory;

	/**
	 * HibernateTemplate 得到保存的实例对象
	 * 
	 * @param null
	 * @return 对象或者null;
	 */
	public Class<T> getPersistentObject() {
		return null;
	}

	/**
	 * 删除对象
	 * 
	 * @param id
	 *            被删除的对象
	 */
	public void deletebyId(Serializable id) {
		Object obj = this.getObject(id);
		this.deleteObject(obj);
	}

	public T get(Class<T> refClass, Serializable key) {
		return hibernateTemplate.get(refClass, key);
	}

	/**
	 * 得到对象
	 * 
	 * @param id
	 *            对象id
	 * @return 对象或者null;
	 */
	public Object getObject(Serializable id) {
		Object o = hibernateTemplate.get(getPersistentObject(), id);
		return o;
	}

	/**
	 * 更新对象
	 * 
	 * @param obj
	 *            被保存的对象
	 */
	public void update(Object obj) {
		hibernateTemplate.saveOrUpdate(obj);
	}

	/**
	 * 保存或者更新对象
	 * 
	 * @param obj
	 *            被保存的对象
	 */
	public void save(Object obj) {
		hibernateTemplate.saveOrUpdate(obj);
	}

	/**
	 * 删除对象
	 * 
	 * @param obj
	 *            被删除的对象
	 */
	public void deleteObject(Object obj) {
		hibernateTemplate.delete(obj);
	}

	/**
	 * 根据 sql 分页参数查询
	 * 
	 * @param obj
	 *            List
	 */
	public List<?> findBySql(final String sql, final int begin, final int count) {
		Session session = getSession(true);
		Query query = session.createSQLQuery(sql);
		if (begin >= 0) {
			query.setFirstResult(begin);
			query.setMaxResults(count);
		}
		List<?> list = query.list();
		releaseSession(session);
		return list;

	}

	/**
	 * 根据 sql 查询
	 * 
	 * @param obj
	 *            List
	 */
	public List<?> findBySql(final String sql) {
		Session session = getSession(true);
		Query query = session.createSQLQuery(sql);
		List<?> list = query.list();
		releaseSession(session);
		return list;
	}

	/**
	 * 根据 hql 查询
	 */
	public List<?> findByHql(String hql) {
		return hibernateTemplate.find(hql);
	}

	/**
	 * 根据 hql 查询
	 */
	public List<?> findByHql(String hql, Object[] params) {
		return hibernateTemplate.find(hql, params);
	}

	/**
	 * 根据查询sql获得记录
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	public int findCountByHql(String hql) {
		int fromIndex = hql.toLowerCase().indexOf("from");
		if (fromIndex != -1) {
			hql = "select count(*) " + hql.substring(fromIndex);
			return ((Long) findByHql(hql).get(0)).intValue();
		} else {
			return 0;
		}
	}

	public String buildCountSql(String sql) {
		int fromIndex = sql.toLowerCase().indexOf("from");
		if (fromIndex != -1) {
			sql = "select count(*) " + sql.substring(fromIndex);
			return sql;
		} else {
			return sql;
		}
	}

	/**
	 * 根据查询sql获得记录
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	public int findCountBySql(final String sql) {
		Session session = getSession(true);
		Query query = session.createSQLQuery(sql);
		List<?> list = query.list();
		releaseSession(session);
		if (list == null) {
			return 0;
		} else {
			return ((BigInteger) list.get(0)).intValue();
		}
	}

	/**
	 * 根据 hql 查询
	 * 
	 * @param obj
	 *            List
	 */
	public List<?> findByHql(final String hql, final int begin, final int count) {
		Session session = getSession(true);
		Query query = session.createQuery(hql);
		if (begin >= 0) {
			query.setFirstResult(begin);
			query.setMaxResults(count);
		}
		List<?> list = query.list();
		releaseSession(session);
		return list;
	}

	/**
	 * 分页带参数根据 hql 查询
	 * 
	 * @param hql
	 *            带有占位参数的hql语句
	 * @param params
	 *            参数值
	 * @param startIndex
	 *            开始索引
	 * @param pageSize
	 *            分页每页记录数
	 * @return
	 */
	public List<?> findByHql(final String hql, final String[] params,
			final int startIndex, final int pageSize) {
		Session session = getSession(true);
		Query query = session.createQuery(hql);
		/* 增加动态参数 */
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i, params[i]);
		}
		if (startIndex >= 0) {
			query.setFirstResult(startIndex);
			query.setMaxResults(pageSize);
		}
		List<?> list = query.list();
		releaseSession(session);
		return list;
	}

	public Log getLog(Class<T> toclass) {
		Log logger = LogFactory.getLog(toclass);
		return logger;
	}

	public SessionFactory getSessionFactory() {
		return (this.hibernateTemplate != null ? this.hibernateTemplate
				.getSessionFactory() : null);
	}

	protected Session getSession(boolean allowCreate)
			throws DataAccessResourceFailureException, IllegalStateException {
		// return (!allowCreate ? SessionFactoryUtils.getSession(
		// getSessionFactory(), false) : SessionFactoryUtils.getSession(
		// getSessionFactory(),
		// this.hibernateTemplate.getEntityInterceptor(),
		// this.hibernateTemplate.getJdbcExceptionTranslator()));
		return sessionFactory.getCurrentSession();
	}

	protected void releaseSession(Session session) {
		// SessionFactoryUtils.releaseSession(session, getSessionFactory());
	}

	/******************************************** 动态参数拼配查询 **********************************************************/

	/**
	 * 分页带参数根据 hql 查询
	 * 
	 * @param hql
	 *            带有占位参数的hql语句
	 * @param params
	 *            参数值 要求hql内动态参数key必须和map里的key保持一致
	 * @param startIndex
	 *            开始索引 如果为负值查询全部
	 * @param pageSize
	 *            分页每页记录数
	 * @return
	 */
	public List<?> findByHql(String hql, Map<String, Object> params,
			int startIndex, int pageSize) {
		Session session = getSession(true);
		Query query = buildHqlQuery(session, hql, params, startIndex, pageSize);
		List<?> list = query.list();
		releaseSession(session);
		return list;
	}

	/**
	 * 根据查询hql查询数据总数目
	 * 
	 * @param hql
	 *            原查询hql 方法自动构建count函数
	 * @param params
	 * @param startIndex
	 * @param pageSize
	 * @return
	 */
	public int findCountByHql(String hql, Map<String, Object> params) {
		System.out.print("run HQL");
		System.out.println("HQL:" + hql);
		System.out.println("params:" + params.toString());
		hql = buildCountSql(hql);
		Session session = getSession(true);
		Query query = buildHqlQuery(session, hql, params, -1, 0);
		List<?> list = query.list();
		releaseSession(session);
		return ((Number) list.get(0)).intValue();
	}

	public List<?> findByHql(String hql, Map<String, Object> params) {
		Session session = getSession(true);
		Query query = buildHqlQuery(session, hql, params, -1, 0);
		List<?> list = query.list();
		releaseSession(session);
		return list;
	}

	private Query buildHqlQuery(Session session, String hql,
			Map<String, Object> params, int startIndex, int pageSize) {
		Query query = session.createQuery(hql);
		/* 增加动态参数 */
		if (params != null) {
			for (Map.Entry<String, Object> entry : params.entrySet()) {
				query.setParameter(entry.getKey(), entry.getValue());
			}
		}
		/* 增加分页 */
		if (startIndex >= 0) {
			query.setFirstResult(startIndex);
			query.setMaxResults(pageSize);
		}
		return query;
	}

	/**
	 * 分页带参数根据 sql 查询
	 * 
	 * @param sql
	 *            带有占位参数的hql语句
	 * @param params
	 *            参数值
	 * @param startIndex
	 *            开始索引 如果为负值查询全部
	 * @param pageSize
	 *            分页每页记录数
	 * @return
	 */
	public List<?> findBySql(String sql, Map<String, Object> params,
			int startIndex, int pageSize) {
		Session session = getSession(true);
		Query query = buildSqlQuery(session, sql, params, startIndex, pageSize);
		List<?> list = query.list();
		releaseSession(session);
		return list;
	}

	/**
	 * 根据查询sql查询数据总数目
	 * 
	 * @param sql
	 *            原查询sql 方法自动构建count函数
	 * @param params
	 * @param startIndex
	 * @param pageSize
	 * @return
	 */
	public int findCountBySql(String sql, Map<String, Object> params) {
		sql = buildCountSql(sql);
		Session session = getSession(true);
		Query query = buildSqlQuery(session, sql, params, -1, 0);
		List<?> list = query.list();
		releaseSession(session);
		return ((Number) list.get(0)).intValue();
	}

	private Query buildSqlQuery(Session session, String hql,
			Map<String, Object> params, int startIndex, int pageSize) {
		Query query = session.createSQLQuery(hql);
		/* 增加动态参数 */
		if (params != null) {
			for (Map.Entry<String, Object> entry : params.entrySet()) {
				query.setParameter(entry.getKey(), entry.getValue());
			}
		}
		/* 增加分页 */
		if (startIndex >= 0) {
			query.setFirstResult(startIndex);
			query.setMaxResults(pageSize);
		}
		return query;
	}

	@Override
	public List<T> findByCriteria(DetachedCriteria criteria) {
		return (List<T>) hibernateTemplate.findByCriteria(criteria);
	}

	@SuppressWarnings("unchecked")
	@Override
	public int findCountByCriteria(final DetachedCriteria criteria) {
		return (Integer) hibernateTemplate.executeWithNativeSession(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException {
				Criteria c = criteria.getExecutableCriteria(session);
				Long l = (Long) c.setProjection(Projections.rowCount()).uniqueResult();
				return l.intValue();
			}
		});
	}

	@SuppressWarnings("unchecked")
	public List<T> findByCriteria(final DetachedCriteria detachedCriteria,
			final int startIndex, final int pageSize) {
		return hibernateTemplate.executeWithNativeSession(new HibernateCallback<List<T>>() {
			public List<T> doInHibernate(Session session)
					throws HibernateException {
				Criteria criteria = detachedCriteria
						.getExecutableCriteria(session);
				criteria.setProjection(null);
				return criteria.setFirstResult(startIndex)
						.setMaxResults(pageSize).list();
			}
		});
	}
}
